package aigle.idm.diagraph.tp3.diagram_default_root.edit.policies;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
import org.eclipse.gmf.runtime.diagram.core.services.ViewService;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeCompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.OpenEditPolicy;
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.HintedDiagramLinkStyle;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.Style;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

/**
 * @generated
 */
public class OpenDiagramEditPolicyingredient_root extends OpenEditPolicy {

	/**
	 * @generated
	 */
	protected Command getOpenCommand(Request request) {
		EditPart targetEditPart = getTargetEditPart(request);
		if (false == targetEditPart.getModel() instanceof View) {
			return null;
		}
		View view = (View) targetEditPart.getModel();
		Style link = view.getStyle(NotationPackage.eINSTANCE
				.getHintedDiagramLinkStyle());
		if (false == link instanceof HintedDiagramLinkStyle) {
			return null;
		}
		return new ICommandProxy(new OpenDiagramCommand(
				(HintedDiagramLinkStyle) link));
	}

	/**
	 * DIAGRAPH modified 103
	 * @generated
	 */
	@Override
	public EditPart getTargetEditPart(Request request) {
		EditPart host = getHost();
		EditPart result = host;
		if (request.getType().toString().equals("autosize")
				&& (host instanceof ShapeCompartmentEditPart)) {
			System.out.println("###a "
					+ result.getClass().getSimpleName()
					+ "  -  "
					+ ((EObject) ((Node) result.getModel()).getElement())
							.getClass().getSimpleName());
		} else if (understandsRequest(request)
				&& (host instanceof ShapeNodeEditPart || host instanceof ConnectionNodeEditPart)) {
			System.out.println("###b "
					+ result.getClass().getSimpleName()
					+ "  -  "
					+ ((EObject) ((Node) result.getModel()).getElement())
							.getClass().getSimpleName());
		} else if (understandsRequest(request)) {
			result = host.getParent();
			System.out.println("###c "
					+ result.getClass().getSimpleName()
					+ "  -  "
					+ ((EObject) ((Node) result.getModel()).getElement())
							.getClass().getSimpleName());
		} else
			result = super.getTargetEditPart(request);
		return result;
	}

	/**
	 * @generated
	 */
	private static class OpenDiagramCommand extends
			AbstractTransactionalCommand {

		/**
		 * @generated
		 */
		private final HintedDiagramLinkStyle diagramFacet;

		/**
		 * @generated
		 */
		OpenDiagramCommand(HintedDiagramLinkStyle linkStyle) {
			// editing domain is taken for original diagram, 
			// if we open diagram from another file, we should use another editing domain
			super(
					TransactionUtil.getEditingDomain(linkStyle),
					aigle.idm.diagraph.tp3.diagram_default_root.part.Messages.CommandName_OpenDiagram,
					null);
			diagramFacet = linkStyle;
		}

		// FIXME canExecute if  !(readOnly && getDiagramToOpen == null), i.e. open works on ro diagrams only when there's associated diagram already

		/**
		 * DIAGRAPH modified 101
		 * @generated
		 */
		protected CommandResult doExecuteWithResult(IProgressMonitor monitor,
				IAdaptable info) throws ExecutionException {
			System.out.println("### open diagram ###"); //FP121023
			try {
				Diagram diagram = getDiagramToOpen();
				if (diagram == null) {
					diagram = intializeNewDiagram();
				}
				URI uri = EcoreUtil.getURI(diagram);
				String editorName = uri.lastSegment() + '#'
						+ diagram.eResource().getContents().indexOf(diagram);
				//FP121023
				IEditorInput editorInput = new URIEditorInput(uri, editorName);
				try {
					System.out.println("### diagram: "
							+ diagram.eResource().getContents().toString());
					System.out.println("### editorName: " + editorName);
					System.out.println("### editorId: " + getEditorID());
				} catch (Exception e) {

				}
				IWorkbenchPage page = PlatformUI.getWorkbench()
						.getActiveWorkbenchWindow().getActivePage();

				for (IEditorReference iEditorReference : page
						.getEditorReferences()) {
					System.out.println("###@@ " + iEditorReference.getName());
					if (editorName.startsWith(iEditorReference.getName() + "#"))
						;//page.hideEditor(iEditorReference);	//hack //FP121109
				}

				// open in a new editor ?  
				page.openEditor(editorInput, getEditorID());
				//((org.eclipse.gmf.runtime.diagram.ui.resources.editor.parts.DiagramDocumentEditor)(page.getActiveEditor())).setInput(editorInput); 
				//open in the current editor, needs navigation  - TODO
				return CommandResult.newOKCommandResult();
			} catch (Exception ex) {
				System.out.println("### can't open diagram ###");
				throw new ExecutionException("Can't open diagram", ex);
			}
		}

		/**
		 * @generated
		 */
		protected Diagram getDiagramToOpen() {
			return diagramFacet.getDiagramLink();
		}

		/**
		 * DIAGRAPH modified 102
		 * @generated
		 */
		protected Diagram intializeNewDiagram() throws ExecutionException {
			System.out.println("### intializeNewDiagram ###"); //FP121023
			try {
				System.out.println("### diagramDomainElement: "
						+ getDiagramDomainElement());
				System.out.println("### diagramKind: " + getDiagramKind());
				System.out.println("### preferencesHint: "
						+ getPreferencesHint().toString());
			} catch (Exception e) {

			}
			Diagram d = ViewService.createDiagram(getDiagramDomainElement(),
					getDiagramKind(), getPreferencesHint());
			if (d == null) {
				System.out.println("### can't create diagram ###");
				throw new ExecutionException("Can't create diagram of '"
						+ getDiagramKind() + "' kind");
			}
			diagramFacet.setDiagramLink(d);
			assert diagramFacet.eResource() != null;
			diagramFacet.eResource().getContents().add(d);
			EObject container = diagramFacet.eContainer();
			while (container instanceof View) {
				((View) container).persist();
				container = container.eContainer();
			}
			try {
				new WorkspaceModifyOperation() {
					protected void execute(IProgressMonitor monitor)
							throws CoreException, InvocationTargetException,
							InterruptedException {
						try {
							for (Iterator it = diagramFacet.eResource()
									.getResourceSet().getResources().iterator(); it
									.hasNext();) {
								Resource nextResource = (Resource) it.next();
								if (nextResource.isLoaded()
										&& !getEditingDomain().isReadOnly(
												nextResource)) {
									nextResource
											.save(aigle.idm.diagraph.tp3.diagram_default_root.part.Tp3DiagramEditorUtil
													.getSaveOptions());
								}
							}
						} catch (IOException ex) {
							throw new InvocationTargetException(ex,
									"Save operation failed");
						}
					}
				}.run(null);
			} catch (InvocationTargetException e) {
				throw new ExecutionException("Can't create diagram of '"
						+ getDiagramKind() + "' kind", e);
			} catch (InterruptedException e) {
				throw new ExecutionException("Can't create diagram of '"
						+ getDiagramKind() + "' kind", e);
			}
			return d;
		}

		/**
		 * DIAGRAPH modified 104
		 * @generated
		 */
		protected EObject getDiagramDomainElement() {
			// use same element as associated with EP
			EObject eobject = ((View) diagramFacet.eContainer()).getElement();
			/*
			if (eobject instanceof Foo) {
				Foo compartmented = (Foo) eobject;
				return inlineModel.getType();
			} else if (eobject instanceof Bar) {
				Bar notCompartmented = (Bar) eobject;
				return notCompartmented.getType();
			}
			 */
			return eobject;
		}

		/**
		 * @generated
		 */
		protected PreferencesHint getPreferencesHint() {
			// XXX prefhint from source diagram's editor !!
			return aigle.idm.diagraph.tp3.diagram_default_root.part.Tp3DiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT;
		}

		/**
		 * @generated
		 */
		protected String getDiagramKind() {
			return "Tp3_ingredient_root";
		}

		/**
		 * @generated
		 */
		protected String getEditorID() {
			return "aigle.idm.diagraph.tp3.diagram_ingredient_root.part.Tp3DiagramEditorID";
		}
	}

}
